"""根据WMS系统的需求，在ODOO里添加某些字段，并添加同步功能"""

from datetime import timedelta

from odoo import models, api, fields
from odoo.tools import float_compare
from odoo.exceptions import UserError, ValidationError


class ProductTemplate(models.Model):
    """产品在创建、修改时同步"""
    _name = 'product.template'
    _inherit = ['product.template', 'nd.wms']

    customer_id = fields.Many2one('res.partner', string="货主", domain=[('can_use', '=', True)])

    @api.model
    def create(self, val):
        res = super().create(val)
        self.push_products_to_wms(res)
        return res

    @api.multi
    def write(self, val):
        res = super().write(val)
        # if not self.env.context.get('no_sync'):
        if self._get_sync_fields().intersection(val.keys()):
            self.push_products_to_wms(self)
        return res


class Partner(models.Model):
    """联系人在创建、修改时同步"""
    _name = 'res.partner'
    _inherit = ['res.partner', 'nd.wms']

    @api.multi
    def manual_sync_partner(self):
        """手动同步"""
        for res in self:
            self.push_partners_to_wms(res)

    @api.model
    def create(self, val):
        res = super().create(val)
        # if not self.env.context.get('no_sync'):
        self.push_partners_to_wms(res)
        return res

    @api.multi
    def write(self, val):
        res = super().write(val)
        # if not self.env.context.get('no_sync'):
        if self._get_sync_fields().intersection(val.keys()):
            self.push_partners_to_wms(self)
        return res


class Sale(models.Model):
    """出库单在确认销售单时同步"""
    _name = 'sale.order'
    _inherit = ['sale.order', 'nd.wms']

    wms_no = fields.Char('WMS系统单号', copy=False)

    @api.multi
    def action_confirm(self):
        res = super().action_confirm()
        if not self.env.context.get('no_sync'):
            pickings = self.mapped('picking_ids')
            self.push_out_stocks_to_wms(pickings)
        return res


class Purchase(models.Model):
    """入库单在确认采购单时同步"""
    _name = 'purchase.order'
    _inherit = ['purchase.order', 'nd.wms']

    wms_no = fields.Char('WMS系统单号', copy=False)

    @api.multi
    def button_confirm(self):
        res = super().button_confirm()
        if not self.env.context.get('no_sync'):
            pickings = self.mapped('picking_ids')
            self.push_in_stocks_to_wms(pickings)
        return res


class Picking(models.Model):
    _name = 'stock.picking'
    _inherit = ['stock.picking', 'nd.wms']

    wms_no = fields.Char('WMS系统单号', copy=False)
    is_consignment_return = fields.Boolean('是否是寄售退回')
    all_money = fields.Float(string='总金额',store=True,compute='change_all')
    all_money_dx = fields.Char(string='总金额大写',store=True,compute='digital_to_chinese')
    all_qty_done = fields.Float(string='总件数',store=True,compute='change_all')

    @api.depends('move_ids_without_package.quantity_done','move_ids_without_package.sale_line_id.price_unit')
    def change_all(self):
        for i in self:
            all = 0
            num = 0
            for line in i.move_ids_without_package:
                all += line.quantity_done * line.sale_line_id.price_unit
                num += line.quantity_done
            i.all_money = all
            i.all_qty_done = num

    @api.depends('all_money')
    def digital_to_chinese(self):
        for x in self:
            str_digital = str(round(x.all_money,2))
            chinese = {'1': '壹', '2': '贰', '3': '叁', '4': '肆', '5': '伍', '6': '陆', '7': '柒', '8': '捌', '9': '玖', '0': '零'}
            chinese2 = ['拾', '佰', '仟', '万', '厘', '分', '角']
            jiao = ''
            bs = str_digital.split('.')
            yuan = bs[0]
            if len(bs) > 1:
                jiao = bs[1]
            r_yuan = [i for i in reversed(yuan)]
            count = 0
            for i in range(len(yuan)):
                if i == 0:
                    r_yuan[i] += '圆'
                    continue
                r_yuan[i] += chinese2[count]
                count += 1
                if count == 4:
                    count = 0
                    chinese2[3] = '亿'

            s_jiao = [i for i in jiao][:3]  # 去掉小于厘之后的

            j_count = -1
            for i in range(len(s_jiao)):
                s_jiao[i] += chinese2[j_count]
                j_count -= 1
            last = [i for i in reversed(r_yuan)] + s_jiao

            last_str = ''.join(last)
            # print(str_digital)
            # print(last_str)
            for i in range(len(last_str)):
                digital = last_str[i]
                if digital in chinese:
                    last_str = last_str.replace(digital, chinese[digital])
            x.all_money_dx = last_str
        # print(last_str)
            return last_str

    @api.multi
    def test_push_in_stock(self):
        self.push_in_stocks_to_wms(self)

    @api.multi
    def test_push_out_stock(self):
        self.push_out_stocks_to_wms(self)

    @api.multi
    def action_cancel(self):
        uncancelled = self.filtered(lambda x: x.state != 'cancel')
        res = super().action_cancel()
        if not self.env.context.get('no_sync'):
            for pick in uncancelled:
                if pick.picking_type_code == 'incoming':
                    self.cancel_in_stocks_to_wms(pick)
                elif pick.picking_type_code == 'outgoing':
                    self.cancel_out_stocks_to_wms(pick)
                # elif pick.is_consignment_return and pick.picking_type_code == 'internal':
                elif pick.picking_type_id == self.env.ref('nd_consignment.nd_consignment_return_picking_type'):
                    # 取消寄售退回单，也要传递到WMS
                    self.cancel_in_stocks_to_wms(pick, consignment_return=True)
                elif pick.picking_type_id == self.env.ref('nd_consignment.nd_consignment_picking_type'):
                    # 寄售单
                    self.cancel_out_stocks_to_wms(pick)
        return res

    @api.multi
    def unlink(self):
        """为了保持和WMS的同步,这里禁止删除"""
        raise UserError('为了保持和WMS系统的同步,禁止删除出入库单据!')


class StockReturnPickingLine(models.TransientModel):
    _inherit = "stock.return.picking.line"

    allowed_lots = fields.Many2many('stock.production.lot', string="允许填写的批次")
    nd_lot_id = fields.Many2one('stock.production.lot', string="退货批次")
    nd_location_dest_id = fields.Many2one('stock.location', string="至")
    nd_location_src_id = fields.Many2one('stock.location', string="从")


class ReturnPicking(models.TransientModel):
    _name = 'stock.return.picking'
    _inherit = ['stock.return.picking', 'nd.wms']

    @api.model
    def default_get(self, fields):
        """插入默认的批次号，和允许的批次号范围"""
        res = super().default_get(fields)
        # [(0, 0, {'move_id': 1}), (...)]
        if 'product_return_moves' in res:
            for data in res['product_return_moves']:
                if len(data) == 3:
                    data_dict = data[2]
                    origin_move = self.env['stock.move'].browse(data_dict['move_id'])
                    lot_ids = origin_move.move_line_ids.mapped('lot_id')
                    location_dest_ids = origin_move.move_line_ids.mapped('location_dest_id')
                    location_src_ids = origin_move.move_line_ids.mapped('location_id')
                    if lot_ids:
                        data_dict['nd_lot_id'] = lot_ids[0].id
                    if location_dest_ids:
                        data_dict['nd_location_src_id'] = location_dest_ids[0].id
                    if location_src_ids:
                        data_dict['nd_location_dest_id'] = location_src_ids[0].id
                    allowed_lines = origin_move.picking_id.move_line_ids.filtered(lambda x: x.product_id.id == data_dict['product_id'])
                    data_dict['allowed_lots'] = [(6, 0, allowed_lines.mapped('lot_id').ids)]
        return res

    def _prepare_move_default_values(self, return_line, new_picking):
        """正常的出库和入库中，理论要求的出入库位置(stock.move上的位置)与实际的出入库位置(stock.move.line上的位置)
        可能不一致（WMS可能修改位置信息），导致退货时退货位置选择的理论位置（stock.move）而非实际位置(stock.move.line)
        进而导致无法自动写入批次信息。这里为了解决这个问题在退货向导的明细里添加了批次字段，便于手动选择，这里
        利用提供的批次信息来强行修改退货位置"""
        res = super()._prepare_move_default_values(return_line, new_picking)
        lot_id = return_line.nd_lot_id
        lines = return_line.move_id.picking_id.move_line_ids.filtered(lambda x: x.product_id == return_line.product_id)
        if lines:
            line = None
            if lot_id:
                line = lines.filtered(lambda x: x.lot_id == lot_id)

            # 2021-3-17，某些情况下，例如批次里的东西被销售完了，则手动选择其他批次来退回，这个批次可能不在此入库单上
            if not line and lines:
                line = lines[0]
            if line:
                res['location_dest_id'] = line.location_id.id
        return res

    def fill_lot_info(self, picking):
        """退货的时候需要调整填充的批次，
        销售退货需要将批次调整成和原来出库的一致
        而采购退货，则和退货向导上填写的一致"""
        # lili 2021-6-9
        if picking.picking_type_code in ['incoming', 'outgoing']:
            for move in picking.move_lines:
                if not move.move_line_ids:
                    sml_val = move._prepare_move_line_vals()
                    self.env['stock.move.line'].create(sml_val)
                line = move.move_line_ids[0]
                return_line = self.product_return_moves.filtered(
                    lambda x: x.move_id == line.move_id.origin_returned_move_id)
                data = {
                    'lot_id': return_line.nd_lot_id.id,
                    'qty_done': return_line.quantity,
                }

                if return_line.nd_location_src_id:
                    data['location_id'] = return_line.nd_location_src_id.id
                if return_line.nd_location_dest_id:
                    data['location_dest_id'] = return_line.nd_location_dest_id.id
                line.write(data)

        # if picking.picking_type_code == 'incoming':
        #     for move in picking.move_lines:
        #         if not move.move_line_ids:
        #             sml_val = move._prepare_move_line_vals()
        #             self.env['stock.move.line'].create(sml_val)
        #         line = move.move_line_ids[0]
        #         return_line = self.product_return_moves.filtered(
        #             lambda x: x.move_id == line.move_id.origin_returned_move_id)
        #         line.write({
        #             'lot_id': return_line.nd_lot_id.id,
        #             'qty_done': return_line.quantity
        #         })
        #
        #         # for line in picking.move_line_ids:
        #         #     return_line = self.product_return_moves.filtered(lambda x: x.move_id == line.move_id.origin_returned_move_id)
        #         #     line.lot_id = return_line.nd_lot_id
        #         #     line.write({
        #         #         'lot_id': return_line.nd_lot_id.id,
        #         #         'qty_done': return_line.quantity
        #         #     })
        # elif picking.picking_type_code == 'outgoing':
        #     for move in picking.move_lines:
        #         if not move.move_line_ids:
        #             # quants = self._gather(product_id, location_id, lot_id=lot_id, package_id=package_id,
        #             #                       owner_id=owner_id, strict=strict)
        #             return_line = self.product_return_moves.filtered(
        #                 lambda x: x.move_id == move.origin_returned_move_id)
        #             # location_id = reserved_quant.location_id.id,
        #             sml_val = move._prepare_move_line_vals()
        #             sml_val['lot_id'] = return_line.nd_lot_id.id or False
        #             sml_val['qty_done'] = return_line.quantity
        #             self.env['stock.move.line'].create(sml_val)

    def _create_returns(self):
        """生成退货时,以不同的类型的出入库单据发送到WMS"""
        new_picking_id, picking_type_id = super()._create_returns()
        picking = self.env['stock.picking'].browse(new_picking_id)
        # 要将批次号也一起传递，所以这里先检查可用量以自动填充批次
        # picking.action_assign()
        picking.do_unreserve()
        self.fill_lot_info(picking)
        if self.picking_id and self.picking_id.picking_type_code == 'incoming':
            # 入库退货(非资产调拨)
            if picking and not self.env['stock.picking'].is_asset_pick(picking):
                self.push_purchase_return_to_wms(picking)
        elif self.picking_id and self.picking_id.picking_type_code == 'internal':
            # 寄售退回
            if picking:
                # 标记为寄售退回，便于后续取消指令传递到WMS
                picking.write({"is_consignment_return": True})
                self.push_consignment_stocks_cancel_to_wms(picking)
        elif self.picking_id and self.picking_id.picking_type_code == 'outgoing':
            # 出库退货(非资产调拨)
            if picking and not self.env['stock.picking'].is_asset_pick(picking):
                self.push_sale_return_to_wms(picking)

        return new_picking_id, picking_type_id


class Inventory(models.Model):
    _inherit = 'stock.inventory'

    wms_no = fields.Char('WMS系统单号', copy=False)


class StockMoveLine(models.Model):
    _inherit = 'stock.move.line'

    nd_production_date = fields.Datetime('生产日期')
    nd_expire_date = fields.Datetime('过期日期')

    def _action_done(self):
        res = super()._action_done()
        for line in self:
            if line.lot_id and line.nd_production_date and line.nd_expire_date:
                life_date, alert_date, removal_date, use_date = self.nd_get_expire_date_info(line.nd_expire_date)
                data = {'life_date': life_date,
                        'alert_date': alert_date,
                        'removal_date': removal_date,
                        'use_date': use_date,
                        'nd_production_date': line.nd_production_date,
                        }
                line.lot_id.write(data)
        return res

    def nd_get_expire_date_info(self, expire_date):
        """根据输入的时间和配置的相关天数,获取过期,下架等日期信息"""
        nd_expire_alert_days = int(self.env['ir.config_parameter'].sudo().get_param('nd.nd_expire_alert_days', default=0))
        nd_expire_move_days = int(self.env['ir.config_parameter'].sudo().get_param('nd.nd_expire_move_days', default=0))
        alert_date = expire_date - timedelta(days=nd_expire_alert_days)
        removal_date = expire_date - timedelta(days=nd_expire_move_days)
        use_date = expire_date - timedelta(days=nd_expire_move_days)
        return expire_date, alert_date, removal_date, use_date









